/*
* WMA compatible codec
* Copyright (c) 2002-2007 The FFmpeg Project
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "wma_audio_codec.h"
#include "wma.h"
#include "wmadata.h"
#include <stdlib.h>

#undef NDEBUG
//#include <assert.h>

/* XXX: use same run/length optimization as mpeg decoders */
//FIXME maybe split decode / encode or pass flag
static void init_coef_vlc(VLC *vlc, uint16_t **prun_table,
                          FIXP **plevel_table, uint16_t **pint_table,
                          const CoefVLCTable *vlc_table)
{
    int n = vlc_table->n;
    const uint8_t  *table_bits   = vlc_table->huffbits;
    const uint32_t *table_codes  = vlc_table->huffcodes;
    const uint16_t *levels_table = vlc_table->levels;
    uint16_t *run_table, *level_table, *int_table;
    FIXP *flevel_table;
    int i, l, j, k, level;
	
    init_vlc(vlc, VLCBITS, n, table_bits, 1, 1, table_codes, 4, 4, 0);
	
    run_table   = malloc(n * sizeof(uint16_t));
    level_table = malloc(n * sizeof(uint16_t));
    flevel_table= malloc(n * sizeof(*flevel_table));
    int_table   = malloc(n * sizeof(uint16_t));
    i = 2;
    level = 1;
    k = 0;
    while (i < n) {
        int_table[k] = i;
        l = levels_table[k++];
        for (j = 0; j < l; j++) {
            run_table[i]   = j;
            level_table[i] = level;
            flevel_table[i]= level;
            i++;
        }
        level++;
    }
    *prun_table   = run_table;
    *plevel_table = flevel_table;
    *pint_table   = int_table;
    av_free(level_table);
}

/**
*@brief Get the samples per frame for this stream.
*@param sample_rate output sample_rate
*@param version wma version
*@param decode_flags codec compression features
*@return log2 of the number of output samples per frame
*/
int av_cold ff_wma_get_frame_len_bits(int sample_rate, int version,
                                      unsigned int decode_flags)
{
	
    int frame_len_bits;
	
    if (sample_rate <= 16000) {
        frame_len_bits = 9;
    } else if (sample_rate <= 22050 ||
		(sample_rate <= 32000 && version == 1)) {
        frame_len_bits = 10;
    } else if (sample_rate <= 48000) {
        frame_len_bits = 11;
    } else if (sample_rate <= 96000) {
        frame_len_bits = 12;
    } else {
        frame_len_bits = 13;
    }
	
    if (version == 3) {
        int tmp = decode_flags & 0x6;
        if (tmp == 0x2) {
            ++frame_len_bits;
        } else if (tmp == 0x4) {
            --frame_len_bits;
        } else if (tmp == 0x6) {
            frame_len_bits -= 2;
        }
    }
	
    return frame_len_bits;
}

int ff_wma_init(WmaAudioContext *avctx, int flags2)
{
    WMACodecContext *s = avctx->priv_data;
    int i;
    FIXP bps1, high_freq;
    volatile FIXP bps;
    int sample_rate1;
    int coef_vlc_table;
	
    if (   avctx->sample_rate <= 0 || avctx->sample_rate > 50000
        || avctx->channels    <= 0 || avctx->channels    > 8
        || avctx->bit_rate    <= 0)
        return -1;
	
    s->sample_rate = avctx->sample_rate;
    s->nb_channels = avctx->channels;
    s->bit_rate    = avctx->bit_rate;
    s->block_align = avctx->block_align;
	
    //dsputil_init(&s->dsp, avctx);
	
    if (avctx->codec_id == CODEC_ID_WMAV11) {
        s->version = 1;
    } else {
        s->version = 2;
    }
	
    /* compute MDCT block size */
    s->frame_len_bits = ff_wma_get_frame_len_bits(s->sample_rate, s->version, 0);
	
    s->frame_len = 1 << s->frame_len_bits;
    if (s->use_variable_block_len) {
        int nb_max, nb;
        nb = ((flags2 >> 3) & 3) + 1;
        if ((s->bit_rate / s->nb_channels) >= 32000)
            nb += 2;
        nb_max = s->frame_len_bits - BLOCK_MIN_BITS;
        if (nb > nb_max)
            nb = nb_max;
        s->nb_block_sizes = nb + 1;
    } else {
        s->nb_block_sizes = 1;
    }
	
    /* init rate dependent parameters */
    s->use_noise_coding = 1;
    high_freq = (s->sample_rate<<(14-1));
	
    /* if version 2, then the rates are normalized */
    sample_rate1 = s->sample_rate;
    if (s->version == 2) {
        if (sample_rate1 >= 44100) {
            sample_rate1 = 44100;
        } else if (sample_rate1 >= 22050) {
            sample_rate1 = 22050;
        } else if (sample_rate1 >= 16000) {
            sample_rate1 = 16000;
        } else if (sample_rate1 >= 11025) {
            sample_rate1 = 11025;
        } else if (sample_rate1 >= 8000) {
            sample_rate1 = 8000;
        }
    }
	
    bps =(int32_t )FIX_DIV16(Q20_CONST(s->bit_rate), (s->nb_channels * s->sample_rate));
    s->byte_offset_bits = av_log2(((FIX_MUL12(bps, s->frame_len) >>3) + Q16_CONST(0.5))>>15) + 2;
	
    /* compute high frequency value and choose if noise coding should
	be activated */
    bps1 = bps;
    if (s->nb_channels == 2)
        bps1 = FIX_MUL30(bps, Q1_CONST(1.6));
    if (sample_rate1 == 44100) {
        if (bps1 >= Q4_CONST(0.61)) {
            s->use_noise_coding = 0;
        } else {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.4));
        }
    } else if (sample_rate1 == 22050) {
        if (bps1 >= Q4_CONST(1.16)) {
            s->use_noise_coding = 0;
        } else if (bps1 >= Q4_CONST(0.72)) {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.7));
        } else {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.6));
        }
    } else if (sample_rate1 == 16000) {
        if (bps > Q4_CONST(0.5)) {
            high_freq = high_freq >> 1;
        } else {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.3));
        }
    } else if (sample_rate1 == 11025) {
        high_freq = FIX_MUL31(high_freq, Q0_CONST(0.7));
    } else if (sample_rate1 == 8000) {
        if (bps <= Q4_CONST(0.625)) {
            high_freq = high_freq >> 1;
        } else if (bps > Q4_CONST(0.75)) {
            s->use_noise_coding = 0;
        } else {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.65));
        }
    } else {
        if (bps >= Q4_CONST(0.8)) {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.75));
        } else if (bps >= Q4_CONST(0.6)) {
            high_freq = FIX_MUL31(high_freq, Q0_CONST(0.6));
        } else {
            high_freq = high_freq >> 1;
        }
    }
	
    /* compute the scale factor band sizes for each MDCT block size */
    {
        int a, b, pos, lpos, k, block_len, i, j, n;
        const uint8_t *table;
		
        if (s->version == 1) {
            s->coefs_start = 3;
        } else {
            s->coefs_start = 0;
        }
        for (k = 0; k < s->nb_block_sizes; k++) {
            block_len = s->frame_len >> k;
			
            if (s->version == 1) {
                lpos = 0;
                for (i = 0; i < 25; i++) {
                    a = ff_wma_critical_freqs[i];
                    b = s->sample_rate;
                    pos = ((block_len * 2 * a) + (b >> 1)) / b;
                    if (pos > block_len)
                        pos = block_len;
                    s->exponent_bands[0][i] = pos - lpos;
                    if (pos >= block_len) {
                        i++;
                        break;
                    }
                    lpos = pos;
                }
                s->exponent_sizes[0] = i;
            } else {
                /* hardcoded tables */
                table = NULL;
                a = s->frame_len_bits - BLOCK_MIN_BITS - k;
                if (a < 3) {
                    if (s->sample_rate >= 44100) {
                        table = exponent_band_44100[a];
                    } else if (s->sample_rate >= 32000) {
                        table = exponent_band_32000[a];
                    } else if (s->sample_rate >= 22050) {
                        table = exponent_band_22050[a];
                    }
                }
                if (table) {
                    n = *table++;
                    for (i = 0; i < n; i++)
                        s->exponent_bands[k][i] = table[i];
                    s->exponent_sizes[k] = n;
                } else {
                    j = 0;
                    lpos = 0;
                    for (i = 0; i < 25; i++) {
                        a = ff_wma_critical_freqs[i];
                        b = s->sample_rate;
                        pos = ((block_len * 2 * a) + (b << 1)) / (4 * b);
                        pos <<= 2;
                        if (pos > block_len)
                            pos = block_len;
                        if (pos > lpos)
                            s->exponent_bands[k][j++] = pos - lpos;
                        if (pos >= block_len)
                            break;
                        lpos = pos;
                    }
                    s->exponent_sizes[k] = j;
                }
            }
			
            /* max number of coefs */
            s->coefs_end[k] = (s->frame_len - ((s->frame_len * 9) / 100)) >> k;
            /* high freq computation */
            s->high_band_start[k] = (FIX64_MUL(block_len<<(1+1), high_freq) / 
				Q17_CONST(s->sample_rate) + 1)>>1;
            n = s->exponent_sizes[k];
            j = 0;
            pos = 0;
            for (i = 0; i < n; i++) {
                int start, end;
                start = pos;
                pos += s->exponent_bands[k][i];
                end = pos;
                if (start < s->high_band_start[k])
                    start = s->high_band_start[k];
                if (end > s->coefs_end[k])
                    end = s->coefs_end[k];
                if (end > start)
                    s->exponent_high_bands[k][j++] = end - start;
            }
            s->exponent_high_sizes[k] = j;
        }
    }
	
	
    /* init MDCT windows : simple sinus window */
    for(i = 0; i < s->nb_block_sizes; i++)
    {
        s->windows[i] = fix_sine_windows[s->frame_len_bits - i];
    }
	
    s->reset_block_lengths = 1;
	
    if (s->use_noise_coding) {
		
        FIXP norm;
        /* init the noise generator */
        if (s->use_exp_vlc) {
            s->noise_shift = 1;
            norm = Q0_CONST(0.02*8.0*1.7320508075689);
        } else {
            s->noise_shift = 2;
            norm = Q0_CONST(0.04*8.0*1.7320508075689);
        }
        {
            unsigned int seed;
            seed = 1;
            for (i = 0; i < NOISE_TAB_SIZE; i++) {
                seed = seed * 314159 + 1;
                s->noise_table[i] = (FIX_MUL32((int)seed, norm));
            }
        }
    }
	
    /* choose the VLC tables for the coefficients */
    coef_vlc_table = 2;
    if (s->sample_rate >= 32000) {
        if (bps1 < Q4_CONST(0.72)) {
            coef_vlc_table = 0;
        } else if (bps1 < Q4_CONST(1.16)) {
            coef_vlc_table = 1;
        }
    }
    s->coef_vlcs[0]= &coef_vlcs[coef_vlc_table * 2    ];
    s->coef_vlcs[1]= &coef_vlcs[coef_vlc_table * 2 + 1];
    init_coef_vlc(&s->coef_vlc[0], &s->run_table[0], &s->level_table[0], &s->int_table[0],
		s->coef_vlcs[0]);
    init_coef_vlc(&s->coef_vlc[1], &s->run_table[1], &s->level_table[1], &s->int_table[1],
		s->coef_vlcs[1]);
    return 0;
}

int ff_wma_total_gain_to_bits(int total_gain)
{
	if (total_gain < 15) return 13;
    else if (total_gain < 32) return 12;
    else if (total_gain < 40) return 11;
    else if (total_gain < 45) return 10;
    else                      return  9;
}

int ff_wma_end(WmaAudioContext *avctx)
{
    WMACodecContext *s = avctx->priv_data;
    int i;
    if(s!=NULL){
		if (s->use_exp_vlc) {
			free_vlc(&s->exp_vlc);
		}
		if (s->use_noise_coding) {
			free_vlc(&s->hgain_vlc);
		}
		for (i = 0; i < 2; i++) {
			free_vlc(&s->coef_vlc[i]);
			av_free(s->run_table[i]);
			av_free(s->level_table[i]);
			av_free(s->int_table[i]);
		}
	}
	if (avctx->wfp!=NULL){
		av_free(avctx->wfp->extradata);
		av_free(avctx->wfp);
	}
    return WMA_DEC_ERR_NoErr;
}

/**
* Decode an uncompressed coefficient.
* @param gb GetBitContext
* @return the decoded coefficient
*/
unsigned int ff_wma_get_large_val(GetBitContext* gb)
{
    /** consumes up to 34 bits */
    int n_bits = 8;
    /** decode length */
    if (get_bits1(gb)) {
        n_bits += 8;
        if (get_bits1(gb)) {
            n_bits += 8;
            if (get_bits1(gb)) {
                n_bits += 7;
            }
        }
    }
    return get_bits_long(gb, n_bits);
}

/**
* Decode run level compressed coefficients.
* @param avctx codec context
* @param gb bitstream reader context
* @param vlc vlc table for get_vlc2
* @param level_table level codes
* @param run_table run codes
* @param version 0 for wma1,2 1 for wmapro
* @param ptr output buffer
* @param offset offset in the output buffer
* @param num_coefs number of input coefficents
* @param block_len input buffer length (2^n)
* @param frame_len_bits number of bits for escaped run codes
* @param coef_nb_bits number of bits for escaped level codes
* @return 0 on success, -1 otherwise
*/
int ff_wma_run_level_decode(WmaAudioContext* avctx, GetBitContext* gb,
                            VLC *vlc,
                            const FIXP *level_table, const uint16_t *run_table,
                            int version, fixWMACoef *ptr, int offset,
                            int num_coefs, int block_len, int frame_len_bits,
                            int coef_nb_bits)
{
    int code, level, sign;
    const unsigned int coef_mask = block_len - 1;
    for (; offset < num_coefs; offset++) {
        code = get_vlc2(gb, vlc->table, VLCBITS, VLCMAX);
        if (code > 1) {
            /** normal code */
            offset += run_table[code];
            sign = get_bits1(gb) - 1;
            ptr[offset & coef_mask] = (level_table[code]^sign) - sign;
        } else if (code == 1) {
            /** EOB */
            break;
        } else {
            /** escape */
            if (!version) {
                level = get_bits(gb, coef_nb_bits);
                /** NOTE: this is rather suboptimal. reading
				block_len_bits would be better */
                offset += get_bits(gb, frame_len_bits);
            } else {
                level = ff_wma_get_large_val(gb);
                /** escape decode */
                if (get_bits1(gb)) {
                    if (get_bits1(gb)) {
                        if (get_bits1(gb)) {
                            //av_log(avctx,AV_LOG_ERROR,"broken escape sequence\n");
                            return -1;
                        } else
                            offset += get_bits(gb, frame_len_bits) + 4;
                    } else
                        offset += get_bits(gb, 2) + 1;
                }
            }
            sign = get_bits1(gb) - 1;
            ptr[offset & coef_mask] = (level^sign) - sign;
        }
    }
    /** NOTE: EOB can be omitted */
    if (offset > num_coefs) {
        //av_log(avctx, AV_LOG_ERROR, "overflow in spectral RLE, ignoring\n");
        return -1;
    }
	
    return 0;
}

